//
//  YTBonjourServer.m
//  YTBonjourKit
//
//  Created by aron on 2020/8/13.
//

#import "YTBonjourServer.h"

@interface YTBonjourServer ()<NSNetServiceDelegate, NSStreamDelegate>

@property (nonatomic) NSNetService *netService;

@end

@implementation YTBonjourServer

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self createService];
    }
    return self;
}

- (void)createService {
    NSString *name =  [UIDevice currentDevice].name;
    self.netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_http._tcp." name:name port:62323];
    self.netService.delegate = self;
    [self.netService scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    NSLog(@"create service with name : %@", name);
}

// MARK: - Public

+ (instancetype)sharedInstance {
    static YTBonjourServer *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [YTBonjourServer new];
    });
    return instance;
}

- (void)startServer {
    [self.netService publishWithOptions:NSNetServiceListenForConnections];
    [self.netService startMonitoring];
}

- (void)stopServer {
    [self.netService stopMonitoring];
    [self.netService stop];
}


// MARK: - NSStreamDelegate

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
    switch (eventCode) {
        case NSStreamEventHasBytesAvailable: {
            uint8_t buffer[1024] = {0};
//            NSInteger byteReads = [((NSInputStream*)aStream) read:buffer maxLength:1024];
            NSString *receiveContent = [NSString stringWithCString:(char *)buffer encoding:NSUTF8StringEncoding];
            NSLog(@"read:%@", receiveContent);
        }
            break;
            
        default:
            break;
    }
}

// MARK: - NSNetServiceDelegate

/* Sent to the NSNetService instance's delegate prior to advertising the service on the network. If for some reason the service cannot be published, the delegate will not receive this message, and an error will be delivered to the delegate via the delegate's -netService:didNotPublish: method.
*/
- (void)netServiceWillPublish:(NSNetService *)sender {
    NSLog(@"====netServiceWillPublish");
}

/* Sent to the NSNetService instance's delegate when the publication of the instance is complete and successful.
*/
- (void)netServiceDidPublish:(NSNetService *)sender {
    NSLog(@"====netServiceDidPublish");
}

/* Sent to the NSNetService instance's delegate when an error in publishing the instance occurs. The error dictionary will contain two key/value pairs representing the error domain and code (see the NSNetServicesError enumeration above for error code constants). It is possible for an error to occur after a successful publication.
*/
- (void)netService:(NSNetService *)sender didNotPublish:(NSDictionary<NSString *, NSNumber *> *)errorDict {
    NSLog(@"====didNotPublish");
}

/* Sent to the NSNetService instance's delegate prior to resolving a service on the network. If for some reason the resolution cannot occur, the delegate will not receive this message, and an error will be delivered to the delegate via the delegate's -netService:didNotResolve: method.
*/
- (void)netServiceWillResolve:(NSNetService *)sender {
    NSLog(@"====netServiceWillResolve");
}

/* Sent to the NSNetService instance's delegate when one or more addresses have been resolved for an NSNetService instance. Some NSNetService methods will return different results before and after a successful resolution. An NSNetService instance may get resolved more than once; truly robust clients may wish to resolve again after an error, or to resolve more than once.
*/
- (void)netServiceDidResolveAddress:(NSNetService *)sender {
    NSLog(@"====netServiceDidResolveAddress");
}

/* Sent to the NSNetService instance's delegate when an error in resolving the instance occurs. The error dictionary will contain two key/value pairs representing the error domain and code (see the NSNetServicesError enumeration above for error code constants).
*/
- (void)netService:(NSNetService *)sender didNotResolve:(NSDictionary<NSString *, NSNumber *> *)errorDict {
    NSLog(@"====didNotResolve");
}

/* Sent to the NSNetService instance's delegate when the instance's previously running publication or resolution request has stopped.
*/
- (void)netServiceDidStop:(NSNetService *)sender {
    NSLog(@"====netServiceDidStop");
}

/* Sent to the NSNetService instance's delegate when the instance is being monitored and the instance's TXT record has been updated. The new record is contained in the data parameter.
*/
- (void)netService:(NSNetService *)sender didUpdateTXTRecordData:(NSData *)data {
    NSLog(@"====didUpdateTXTRecordData");
}
    
    
/* Sent to a published NSNetService instance's delegate when a new connection is
 * received. Before you can communicate with the connecting client, you must -open
 * and schedule the streams. To reject a connection, just -open both streams and
 * then immediately -close them.
 
 * To enable TLS on the stream, set the various TLS settings using
 * kCFStreamPropertySSLSettings before calling -open. You must also specify
 * kCFBooleanTrue for kCFStreamSSLIsServer in the settings dictionary along with
 * a valid SecIdentityRef as the first entry of kCFStreamSSLCertificates.
 */
- (void)netService:(NSNetService *)sender didAcceptConnectionWithInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0)) {
    NSLog(@"====didAcceptConnectionWithInputStream");
    
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

    [inputStream open];
    [outputStream open];
    
    inputStream.delegate = self;
    
//    dispatch_async(dispatch_get_global_queue(DISPATCH_PROC_EXEC, 0), ^{
//        uint8_t buffer[1024];
//        if ([inputStream hasBytesAvailable]) {
//            NSInteger bytesRead = [inputStream read:buffer maxLength:1024];
//
//            NSString *receiveContent = [NSString stringWithCharacters:buffer length:bytesRead];
//            NSLog(@"===receiveContext:%@", receiveContent);
//        }
//    });
    
}
@end
